package netty.test13GroupChat;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.text.SimpleDateFormat;

public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> {

    //定义一个channel 组，管理所有的channel，参数GlobalEventExecutor.INSTANCE 是一个全局的事件执行器，是一个单例
    //这个 ChannelGroup 保存了所有的channel ,但是没法区分那个channel,如果想做单聊的这种一对一的聊天，就没法
    //在用这个了，可以用ConcurrenHashMap 代替
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);


    /**
     * 真正的读取数据
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        //1 获取channel
        final Channel channel = ctx.channel();
        //2,这时遍历 channelGroup,根据不同情况，回送不同的消息
        for(Channel ch:channelGroup){
            if(channel !=ch){//说明不是当前channel(也就是不是当前客户端连接的channel)
                ch.writeAndFlush("客户端："+channel.remoteAddress()+" 给 "
                        +ch.remoteAddress()+" 发送了消息"+msg+"\n");
            }else{//给自己提示
                ch.writeAndFlush("自己发送了消息："+msg);
            }
        }
    }

    /**
     * 连接：第一个被调用的方法（表示连接建立，一旦连接，第一个被执行的方法）
     * 这里操作，一旦连接被建立，把连接加入到  channelGroup
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();

        //加入到聊天后，将该客户加入聊天的信息推送给其他的用户，这里一般的想法是遍历channelGroup，分别
        //发消息，但是netty 提供了一个群发的方法   channelGroup.writeAndFlush,注意 在
        //channelGroup.add 之前执行，否则 ，会给当前channel 也发一份
        channelGroup.writeAndFlush("客户端--"+channel.remoteAddress()+" 加入聊天");

        channelGroup.add(channel);

    }

    /**
     * 断开连接会被调用
     * 这里提示xxx客户离开,通知所有人，这里一旦触发了，handlerRemoved
     * 会自动把 Channel 从 channelGroup中移除，不需要再手动 从 channelGroup 中remove了
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channelGroup.writeAndFlush("客户端--"+channel.remoteAddress()+"离开了");

    }
    /**
     * 表示channel 处于活动状态（提示xxx 上线，一般给服务器用）
     * 这里服务器打印一个提示，不用再给客户端提示了，因为handlerAdded
     * 中已经提示了
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().remoteAddress()+" 上线了");
    }

    /**
     * 会在channel 处于不活动状态，会触发这个方法（会自动把当前channel 从channelGroup中移除）
     * 表示离线
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().remoteAddress()+" 离线了");
    }

    /**
     * 发生异常后的消息
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //出现异常后关闭 通道（关闭当前通道？）
        ctx.close();
    }

}
